using IQIGame.Onigao.Framework;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace IQIGame.Onigao.Game
{
    public partial class UIManager : FrameMonoModule
    {
        /// <summary>
        /// 根节点
        /// </summary>
        private Transform _uiRoot;

        public Transform UIRoot => _uiRoot;

        /// <summary>
        /// 根canvas
        /// </summary>
        private Canvas _rootCanvas;

        public Canvas RootCanvas => _rootCanvas;

        /// <summary>
        /// CanvasScaler全局唯一
        /// </summary>
        private CanvasScaler _uiCanvasScaler;

        public CanvasScaler UICanvasScaler => _uiCanvasScaler;
        private Camera _uiCamera;
        public Camera UICamera => _uiCamera;

        Camera _mainCam;

        public Camera MainCamera
        {
            get
            {
                if (_mainCam == null || _mainCam.gameObject.activeInHierarchy == false)
                {
                    _mainCam = Camera.main;
                }

                return _mainCam;
            }
        }

        public Vector2 BackgroundCullSize { get; private set; }

        public Vector2 MovieCullSize { get; private set; }
        public Vector2 BackgroundStretchSize { get; private set; }

        public float MatchWidthOrHeight { get; private set; }

        /// <summary>
        /// 持有所有UI界面的层级根
        /// </summary>
        private RectTransform[] _uiLayoutLevelRoot;

        #region 刘海异形屏适配

        //最大缺口高度
        public float MaxNotchValue { get; set; } = 6f;

        //当前缺口高度
        private float _notchLeftOrTop = 0;

        public float notchLeftOrTop
        {
            get { return this._notchLeftOrTop; }
            set { this._notchLeftOrTop = Mathf.Clamp(value, 0, MaxNotchValue); }
        }

        private float _notchRightOrBottom = 0;

        public float notchRightOrBottom
        {
            get { return this._notchRightOrBottom; }
            set { this._notchRightOrBottom = Mathf.Clamp(value, 0, MaxNotchValue); }
        }

        protected void SetRootLayoutNotch()
        {
            for (int i = 0; i < this._uiLayoutLevelRoot.Length; i++)
            {
                RectTransform transform = _uiLayoutLevelRoot[i];
                if (transform != null)
                {
                    this.SetNotchTransfrom(transform);
                }
            }
        }

        //设置当前RectTansfrom缺口
        public void SetNotchTransfrom(RectTransform rectTran)
        {
            float rateNotchTop = this.notchLeftOrTop / 100;
            float rateNotchBot = this.notchRightOrBottom / 100;

            Vector2 anchorMin = new Vector2(rateNotchTop, 0);
            Vector2 anchorMax = new Vector2(1 - rateNotchBot, 1);
            rectTran.anchorMin = anchorMin;
            rectTran.anchorMax = anchorMax;
        }

        #endregion

        #region 锁频-全屏遮罩

        [SerializeField]
        private UINoDrawRaycast _lockMask;

        public void ChangeLockMaskState(bool isLock)
        {
            if (this._lockMask != null) this._lockMask.raycastTarget = isLock;
        }

        #endregion

        #region 分屏适配

        //允许屏幕尺寸改变
        public bool EnableScreenSizeChange { get; set; } = true;

        //用于编辑器模拟手机上分屏改变屏幕尺寸
        private int _lastWidth = 0;
        private int _lastHeight = 0;

        public event Action onScreenSizeChanged;

        //反射调用Canvas更新
        private System.Reflection.MethodInfo _methodCanvasUpdate;

        #endregion

        protected override void OnInit()
        {
            cacheUIHelper = new CacheUIHelper(GetWindow, RecoverWindowAsync);
            //初始化反射
            Type typeCanvasScaler = typeof(CanvasScaler);
            _methodCanvasUpdate = typeCanvasScaler.GetMethod("Update",
                System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
            //对象引用初始化
            _uiRoot = this.transform;
            _uiCamera = GameObject.Find("GameLaunch/UICamera").GetComponent<Camera>();
            _rootCanvas = _uiRoot.GetComponent<Canvas>();
            // _rootCanvas.planeDistance = _uiCamera.farClipPlane - 10; // 默认是100
            _rootCanvas.worldCamera = _uiCamera;
            _uiCanvasScaler = _uiRoot.GetComponent<CanvasScaler>();
            // 初始化层级
            int cnt = (int)EUILayer.MaxLength;
            _uiLayoutLevelRoot = new RectTransform[cnt];
            _allLayerWindows = new List<UIBaseWindow>[cnt];
            for (int i = 0; i < cnt; i++)
            {
                //RectTransform t = new GameObject(e).AddComponent<RectTransform>();
                //t.SetParent(this._uiRoot);
                //UICoreHelper.ResetRootTransform(t);

                _uiLayoutLevelRoot[i] = _uiRoot.GetChild(i) as RectTransform;
                _allLayerWindows[i] = new List<UIBaseWindow>();
            }

            //屏幕尺寸
            _lastWidth = Screen.width;
            _lastHeight = Screen.height;

            notchLeftOrTop = UIAdaptation.GetDefaultNotchLeftOrTop();
            notchRightOrBottom = UIAdaptation.GetDefaultNotchRightOrBottom();
            CalcScreenAdapter();

            InitMaxMask();

            FrameworkEntry.MonoDriver.updateEvent += OnUpdate;
            FrameworkEntry.MonoDriver.lateUpdateEvent += OnLateUpdate;
        }

        //加载UI时的全局遮罩
        private void InitMaxMask()
        {
            if (_lockMask == null)
                _lockMask = this._uiRoot.GetComponentInChildren<UINoDrawRaycast>(true);
            if (this._lockMask != null)
            {
                var rect = _lockMask.rectTransform;
                rect.sizeDelta = BackgroundStretchSize;
                ChangeLockMaskState(false);
            }
        }

        protected override void OnEnterGame()
        {
        }

        protected override void OnShutdown()
        {
            FrameworkEntry.MonoDriver.updateEvent -= OnUpdate;
            FrameworkEntry.MonoDriver.lateUpdateEvent -= OnLateUpdate;
        }

        private void OnUpdate(float deltaTime, float unscaleTime)
        {
            UpdateScreenSize();

            this.InvokeKeyEvent();

            this.OnUpdate4Windows(deltaTime, unscaleTime);
        }

        private void OnLateUpdate()
        {
            this.OnLateUpdate4Windows();
            this.OnLateUpdate4OptimizeFullScreen();
        }

        private void CalcScreenAdapter()
        {
            //UI适配
            LogGame.Log($"Screen size:{Screen.width} {Screen.height}");
            MatchWidthOrHeight = UIAdaptation.AdaptationCanvasScaler();
            Vector2 referenceResolution = UICanvasScaler.referenceResolution;
            AdaptationCanvasScaler(UICanvasScaler);
            BackgroundStretchSize = UIAdaptation.GenerateBackgroundStretchSize(referenceResolution);
            BackgroundCullSize = UIAdaptation.GenerateBackgroundCullSize(BackgroundStretchSize);
            MovieCullSize = UIAdaptation.GenerateMovieCullSize(BackgroundStretchSize);

            this.SetRootLayoutNotch();
        }

        //强制适配CanvasScaler，在一帧中完成
        public void AdaptationCanvasScaler(CanvasScaler canvasScaler, bool forceUpdate = false)
        {
            canvasScaler.matchWidthOrHeight = MatchWidthOrHeight;
            if (forceUpdate)
            {
                // Canvas.ForceUpdateCanvases();
                _methodCanvasUpdate?.Invoke(canvasScaler, null);
            }
        }

        private void UpdateScreenSize()
        {
            if (!EnableScreenSizeChange)
            {
                return;
            }

            //判断手机屏幕尺寸变化的时候，需要刷新下
            int curWidth = Screen.width;
            int curHeight = Screen.height;
            if (curWidth != _lastWidth || curHeight != _lastHeight)
            {
                _lastWidth = curWidth;
                _lastHeight = curHeight;
                OnMutilWindowStateChanged();
            }
        }

        //当分屏的时候，窗口大小改变的时候
        public void OnMutilWindowStateChanged()
        {
            CalcScreenAdapter();
            //MsgDispatcher.Broadcast(MsgEventType.OnScreenSizeChanged);
            onScreenSizeChanged?.Invoke();
        }

        #region public interface

        public Transform GetUILayoutLevelRoot(EUILayer layoutLevel)
        {
            return _uiLayoutLevelRoot[(int)layoutLevel];
        }

        /// <summary>
        /// 世界坐标转UI坐标
        /// </summary>
        /// <param name="worldPosition">世界坐标</param>
        /// <param name="inCamBack">世界坐标是否在UI相机背面</param>
        /// <param name="rect">ui坐标相对位置依据，不传则使用UIRoot</param>
        /// <param name="uiCam">ui相机，不传默认UI主相机</param>
        /// <param name="mainCam">场景相机，不传默认场景主相机</param>
        /// <returns>相对于rect的localPosition</returns>
        public Vector2 World2UIPosition(Vector3 worldPosition, out bool inCamBack, RectTransform rect = null,
            Camera uiCam = null, Camera mainCam = null)
        {
            inCamBack = false;
            if (!mainCam)
                mainCam = MainCamera;
            if (!mainCam)
            {
                LogGame.LogError("Main camera is none!");
                return Vector2.zero;
            }
            else
            {
                var sPos = mainCam.WorldToScreenPoint(worldPosition);
                //sPos /= RenderManager.GetUIRatio(mainCam);    //世界相机有将分辨率的情况
                var localPoint = Screen2UIPosition(sPos, rect, uiCam);
                if (sPos.z < 0)
                {
                    //在相机背面
                    inCamBack = true;
                    //类似小孔成像原理，图像会颠倒过来，x、y需要取负号
                    localPoint.x *= -1;
                    localPoint.y *= -1;
                }

                return localPoint;
            }
        }

        /// <summary>
        /// 世界坐标转UI坐标
        /// </summary>
        /// <param name="worldPosition">世界坐标</param>
        /// <param name="rect">ui坐标相对位置依据，不传则使用UIRoot</param>
        /// <param name="uiCam">ui相机，不传默认UI主相机</param>
        /// <returns>相对于rect的localPosition</returns>
        public Vector2 World2UIPosition(Vector3 worldPosition, RectTransform rect = null, Camera uiCam = null)
        {
            if (this.MainCamera == null)
            {
                LogGame.LogError("Main camera is none!");
                return Vector2.zero;
            }
            var sPoint = this.MainCamera.WorldToScreenPoint(worldPosition);
            return this.Screen2UIPosition(sPoint, rect, uiCam);
        }

        /// <summary>
        /// 世界坐标转UI坐标
        /// </summary>
        /// <param name="worldPosition">世界坐标</param>
        /// <param name="keepInScreenPixelMarginX">需要保持在屏幕范围内时，x方向与屏幕边缘的最小距离(像素)</param>
        /// /// <param name="keepInScreenPixelMarginY">需要保持在屏幕范围内时，y方向与屏幕边缘的最小距离(像素)</param>
        /// <param name="rect">ui坐标相对位置依据，不传则使用UIRoot</param>
        /// <param name="uiCam">ui相机，不传默认UI主相机</param>
        /// <returns>相对于rect的localPosition</returns>
        public Vector2 World2UIPosition(Vector3 worldPosition, float keepInScreenPixelMarginX, float keepInScreenPixelMarginY, RectTransform rect = null,
            Camera uiCam = null)
        {
            if (this.MainCamera == null)
            {
                LogGame.LogError("Main camera is none!");
                return Vector2.zero;
            }
            var screenPos = this.MainCamera.WorldToScreenPoint(worldPosition);
            var width = Screen.width;
            var height = Screen.height;
            // 检查 z 值，确保对象在相机前面
            if (screenPos.z > 0)
            {
                // 限制 x 和 y 在屏幕范围内
                screenPos.x = Mathf.Clamp(screenPos.x, keepInScreenPixelMarginX, width - keepInScreenPixelMarginX);
                screenPos.y = Mathf.Clamp(screenPos.y, keepInScreenPixelMarginY, height - keepInScreenPixelMarginY);
            }
            else
            {
                // 处理对象在相机后面的情况
                // x永远贴近屏幕边缘，提示玩家转向
                screenPos.x = Mathf.Clamp(width - screenPos.x, keepInScreenPixelMarginX,
                    width - keepInScreenPixelMarginX);
                screenPos.y = Mathf.Clamp(height - screenPos.y, keepInScreenPixelMarginY,
                    height - keepInScreenPixelMarginY);
            }

            return this.Screen2UIPosition(screenPos, rect, uiCam);
        }


        /// <summary>
        /// 屏幕坐标转ui坐标
        /// </summary>
        /// <param name="screenPoint">屏幕坐标</param>
        /// <param name="rect">ui坐标相对位置依据，不传则使用UIRoot</param>
        /// <param name="cam">ui相机，不传默认UI主相机</param>
        /// <returns>相对于rect的localPosition</returns>
        public Vector2 Screen2UIPosition(Vector2 screenPoint, RectTransform rect = null, Camera cam = null)
        {
            RectTransformUtility.ScreenPointToLocalPointInRectangle(rect ? rect : UIRoot as RectTransform,
                screenPoint, cam ? cam : UICamera, out var localPoint);

            return localPoint;
        }

        /// <summary>
        /// 屏幕坐标转世界坐标
        /// </summary>
        /// <param name="screenPoint">屏幕坐标</param>
        /// <param name="rect">ui坐标相对位置依据，不传则使用UIRoot</param>
        /// <param name="cam">ui相机，不传默认UI主相机</param>
        /// <returns></returns>
        public Vector3 Screen2WorldPosition(Vector2 screenPoint, RectTransform rect = null, Camera cam = null)
        {
            RectTransformUtility.ScreenPointToWorldPointInRectangle(rect ? rect : UIRoot as RectTransform,
                screenPoint, cam ? cam : UICamera, out var worldPoint);
            return worldPoint;
        }

        #endregion
    }
}